package gui;

import java.io.File;
import java.io.IOException;

import org.w3c.dom.*;

import conference.Conference;
import conference.Manuscript;
import conference.Author;
import conference.ProgramChair;
import conference.Review;
import conference.Reviewer;

import java.text.DateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException; 

/**
 * 
 * @author Rob Oesch
 *
 */
public class ConsumeXMLData {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		//extractConferences("conferences.xml", true);
		
		/*
		ViewManuscriptGui gui = 
			new ViewManuscriptGui("conferences.xml", 1);
		*/
		if (args.length > 0 && args[0].length() > 0 && args[1].length() > 0) {
			ViewManuscriptPanel guiFromCommandLine = 
				new ViewManuscriptPanel(args[0], 
						Integer.parseInt(args[1]));
		}
		else {
			ViewManuscriptPanel gui = 
				new ViewManuscriptPanel("conferences.xml", 0);
		}
			
	}
	
	/**
	 * Extract conference information from an XML file
	 * @param the_filename Name and Location of the source file
	 * @param printDebugToCommandLine for troubleshooting
	 * @return a List of the conferences in the XML file
	 */
	public static List<Conference> extractConferences(
			String the_filename, 
			boolean printDebugToCommandLine){
		
		List<Conference> conferences = 
			new ArrayList<Conference>();
		
		try {
			DocumentBuilderFactory docBuilderFactory = 
				DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = 
            	docBuilderFactory.newDocumentBuilder();
            
            if (printDebugToCommandLine)
            	System.out.println("Parsing from file '" 
            			+ the_filename + "' ...");
            
            Document doc = docBuilder.parse (
            		new File(the_filename));

            // normalize text representation
            doc.getDocumentElement().normalize();
            
            //Setup the date format
            df = new java.text.SimpleDateFormat(
            		doc.getDocumentElement().
            		getAttribute("date_format"));
            
            NodeList conferenceList = 
            	doc.getElementsByTagName("conference");
            
            int totalConferences = 
            	conferenceList.getLength();
            
            if (printDebugToCommandLine)
            	System.out.println(
            			"Total number of conferences - " 
            			+ totalConferences);

            for (int c=0; c < totalConferences; c++){
            	String conferenceTitle = "";
            	Date conferenceDate = null;
            	Date reviewDeadline = null;
            	Date manuscriptDeadline = null;
            	
            	Element conferenceElement = 
            		(Element)conferenceList.item(c);
            	conferenceTitle = 
            		getAttribute(conferenceElement, 
            				"title");
            	conferenceDate = 
            		parseDate(getAttribute(
            				conferenceElement, 
            				"date"));
            	reviewDeadline = 
            		parseDate(getAttribute(
            				conferenceElement, 
            				"review_deadline"));
            	manuscriptDeadline = 
            		parseDate(getAttribute(
            				conferenceElement, 
            				"manuscript_deadline"));

            	if (printDebugToCommandLine){
            		System.out.println(
            				"Conference - "	
            				+ conferenceTitle);
            		if (conferenceDate != null)
            			System.out.println(
            					"Conference Date - " 
            					+ conferenceDate.toString());
            		if (manuscriptDeadline != null)
            			System.out.println(
            					"Manuscript Deadline - " 
            					+ manuscriptDeadline.toString());
            		if (reviewDeadline != null)
            			System.out.println("Review Deadline - " 
            					+ reviewDeadline.toString());
            	}
            	
            	List<ProgramChair> pcList = new ArrayList<ProgramChair>();
            	NodeList pcNodeList = conferenceElement.getElementsByTagName("program_chair");
            	/*for (int p=0; p < pcNodeList.getLength(); p++) {
            		Node pcNode = pcNodeList.item(p);
            		ProgramChair pc = new ProgramChair(
            				getInnerText(pcNode, "first_name"),
            				getInnerText(pcNode, "last_name"),
            				getInnerText(pcNode, "email"));
            		pcList.add(pc);
            	}*/
            	for (int p=0; p < pcNodeList.getLength(); p++) {
            		Node pcNode = pcNodeList.item(p);
            		ProgramChair pc = new ProgramChair(
            				getAttribute((Element)pcNode, "first_name"),
            				getAttribute((Element)pcNode, "last_name"),
            				getAttribute((Element)pcNode, "email"));
            		pcList.add(pc);
            	}
            		
            	List<Manuscript> manuscripts = 
            		new ArrayList<Manuscript>();
            	
           		NodeList manuscriptList = 
           			conferenceElement.getElementsByTagName("manuscript");
           		
           		for (int m=0; m < manuscriptList.getLength(); m++) {
           			Node manuscriptNode = manuscriptList.item(m);
           			
           			Author newAuthor = 
           				new Author(
           					getInnerText(
           						manuscriptNode, 
           						"author_first_name"),
           					getInnerText(
           						manuscriptNode, 
           						"author_last_name"), 
           					"");
           			
           			Manuscript newManuscript = 
           				new Manuscript(newAuthor, getInnerText(manuscriptNode, "text"), 
           					getAttribute(
           							(Element)manuscriptNode, 
           							"title"));
           			
           			if (printDebugToCommandLine)
           				System.out.println
           				("   Manuscript - " + newManuscript.getTitle() 
           						+ ", by " 
           						+ newManuscript.getCreator().getLastName());
           			
           			NodeList reviewList = 
           				((Element)manuscriptNode).getElementsByTagName("review");
           			List<Review> reviews = 
           				new ArrayList<Review>();
           			
           			for (int r=0; r < reviewList.getLength(); r++) {
           				Node reviewNode = reviewList.item(r);
           				
           				Reviewer newReviewer = 
           					new Reviewer(getInnerText(reviewNode, "reviewer_first_name"),
           						getInnerText(reviewNode, "reviewer_last_name"), "");
           				
           				reviews.add(new Review("", getInnerText(reviewNode, "text"), newReviewer));
           				           				
           				if (printDebugToCommandLine)
           					System.out.println ("       Reviewer - " + getInnerText(reviewNode, "reviewer") +
           						"  Is Complete? " + (getInnerText(reviewNode, "text").length() == 0 ? "No" : "Yes"));
           			}
           			
           			manuscripts.add(new Manuscript(newManuscript, reviews));
           		}
           		
           		conferences.add(new Conference(
           				conferenceTitle, 
           				manuscriptDeadline, 
           				reviewDeadline, 
           				conferenceDate, 
           				manuscripts,
           				pcList));
            }

        }catch (SAXParseException err) {
        System.out.println ("** Parsing error" + ", line " 
             + err.getLineNumber () + ", uri " + err.getSystemId ());
        System.out.println(" " + err.getMessage ());

        }catch (SAXException e) {
        Exception x = e.getException ();
        ((x == null) ? e : x).printStackTrace ();

        }catch (Throwable t) {
        t.printStackTrace ();
		}
        
        if (printDebugToCommandLine) {
        	System.out.println("Parsing Complete");
        	System.out.println("Results - Number of Conferences: " + conferences.size());
        	for (int c=0; c<conferences.size(); c++){
        		Conference conf = conferences.get(c);
        		System.out.println(conf.getTitle());
        		Manuscript[] manuscripts = conf.getAllManuscripts();
        		for (int m=0; m<manuscripts.length; m++) {
        			System.out.println(" -" + manuscripts[m].getTitle());
        		}
        	}
        }
		
		return conferences;
	}
	
	/**
	 * Update the XML datastore file with new information for a conference.
	 * <pre>
	 * - precondition : the_conference != null
	 * - precondition : the_filename != null
	 * - precondition : new java.io.FileWriter(the_filename) != IOException
	 * </pre>
	 * @param the_conference that is to be updated
	 * @param the_filename where the XML datastore is located
	 * @param printDebugToCommandLine show or hide debug info on the command line
	 */
	public static void updateConference(
			Conference the_conference,
			String the_filename, 
			boolean printDebugToCommandLine){
		
		String oldConferenceXML = "";
		String newConferenceXML = convertConferenceToXML(the_conference);
		
				
		//establish the file
		File f = new File(the_filename);
		
		//if the file already exists, then get all of the other conferences that did not change
		if (f.exists()){
			List<Conference> confs = ConsumeXMLData.extractConferences(the_filename, printDebugToCommandLine);
			for (Conference c : confs){
				if (!c.getTitle().equals(the_conference.getTitle()))
					oldConferenceXML += convertConferenceToXML(c);
			}
			f.delete();
		}
		
		f = null;
		
		try {
			java.io.FileWriter fw;
			fw = new java.io.FileWriter(the_filename);
			fw.write("<conferences date_format='MM/dd/yyyy'>" 
					+ newConferenceXML 
					+ oldConferenceXML 
					+ "</conferences>");
			fw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
	}
	
	private static DateFormat df = null;
	
	private static String getInnerText(Node the_node, String the_tagName){

		String returnVal = "";
		
		if (the_node.getNodeType() == Node.ELEMENT_NODE){
			Element an_element = (Element)the_node;
			if (an_element.getElementsByTagName(the_tagName).getLength() > 0) {
				if (an_element.getElementsByTagName(the_tagName).item(0).getChildNodes().getLength() > 0) {
					returnVal = an_element.getElementsByTagName(the_tagName).item(0).getChildNodes().item(0).getNodeValue();
				}
			}
		}
		
		return returnVal;
		
	}
	
	private static String getAttribute(Element the_element, String the_attribute_name){
		String returnVal = null;
		
		if (the_element.hasAttribute(the_attribute_name))
			returnVal = the_element.getAttribute(the_attribute_name);
		
		return returnVal;
	}
	
	private static Date parseDate(String the_date){
		Date returnVal = null;
		
		if (the_date != null && the_date.trim().length() != 0)
			try {
				returnVal = df.parse(the_date.trim());
			} catch (ParseException e) {
				//ignore
			}
		
		return returnVal;
	}
	
	/**
	 * Take a Conference object and convert it to XML string value for storing in file
	 * <pre>
	 * - precondition : the_conference != null
	 * </pre>
	 * @param the_conference that is to be converted
	 * @return string representation of the conference object
	 */
	private static String convertConferenceToXML(Conference the_conference){
		String dateFormat = "MM/dd/yyyy";
		//Setup the date format
        df = new java.text.SimpleDateFormat(dateFormat);
		
		java.lang.StringBuilder conferenceXML = new java.lang.StringBuilder();
		
		//convert conference object to XML representation
		conferenceXML.append("<conference title='" + the_conference.getTitle() + "' "
				+ "date='" + df.format(the_conference.getConferenceDeadline()) + "' "
				+ "manuscript_deadline='" + df.format(the_conference.getManuscriptDeadline()) + "' "
				+ "review_deadline='" + df.format(the_conference.getReviewDeadline()) + "'>");
	
		//Add Program Chairs
		for (ProgramChair p : the_conference.getProgramChairs()){
			conferenceXML.append("<program_chair first_name='" + p.getFirstName() + "' "
					+ "last_name='" + p.getLastName() + "' "
					+ "email='" + p.getEmail() + "'/>");
		}
		
		for (Manuscript m : the_conference.getAllManuscripts()){
			conferenceXML.append("<manuscript title='" + m.getTitle() + "'>");
			
			//Add Author
			if (m.getAuthor() != null){
				conferenceXML.append("<author_first_name>" + m.getAuthor().getFirstName() + "</author_first_name>");
				conferenceXML.append("<author_last_name>" + m.getAuthor().getLastName() + "</author_last_name>");
			}
			
			//Add text of Manuscript
			conferenceXML.append("<text>" + m.getFileContents() + "</text>");
			
			//Add Reviews
			for (Review r : m.getReviews()){
				conferenceXML.append("<review>");
				if (r.getReviewer() != null){
					conferenceXML.append("<reviewer_first_name>" + r.getReviewer().getFirstName() + "</reviewer_first_name>");
					conferenceXML.append("<reviewer_last_name>" + r.getReviewer().getLastName() + "</reviewer_last_name>");
				}
				conferenceXML.append("<text>" + r.getFileContents() + "</text>");
				conferenceXML.append("</review>");
			}
			
			conferenceXML.append("</manuscript>");
		}
		
		conferenceXML.append("</conference>");
		
		return conferenceXML.toString();
	}

}
